package com.yami.shop.manager.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayConstants;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.binarywang.wxpay.bean.notify.*;
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.paypal.orders.OrdersCreateRequest;
import com.yami.shop.bean.app.dto.LedgerOrderDto;
import com.yami.shop.bean.app.param.PayInfoParam;
import com.yami.shop.bean.app.param.PayXsCountOrderParam;
import com.yami.shop.bean.bo.PayInfoResultBO;
import com.yami.shop.bean.bo.RefundInfoBo;
import com.yami.shop.bean.enums.BackType;
import com.yami.shop.bean.enums.DivideStatus;
import com.yami.shop.bean.enums.PayStatus;
import com.yami.shop.bean.event.BalancePayEvent;
import com.yami.shop.bean.event.BalanceRefundEvent;
import com.yami.shop.bean.model.PayInfo;
import com.yami.shop.bean.model.PayOrderDivisionRecord;
import com.yami.shop.bean.model.ShopDivisionReceiver;
import com.yami.shop.bean.param.PayPalOrderParam;
import com.yami.shop.bean.param.WebhookParam;
import com.yami.shop.bean.param.hnaPay.BaseTransForm;
import com.yami.shop.bean.pay.PayInfoDto;
import com.yami.shop.bean.pay.RefundInfoDto;
import com.yami.shop.common.bean.Domain;
import com.yami.shop.common.bean.RequestKitBean;
import com.yami.shop.common.bean.SysPayConfig;
import com.yami.shop.common.bean.WxPay;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.enums.PayType;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.response.ServerResponseEntity;
import com.yami.shop.common.util.*;
import com.yami.shop.config.*;
import com.yami.shop.dao.PayInfoMapper;
import com.yami.shop.service.PayOrderDivisionRecordService;
import com.yami.shop.service.ShopDivisionReceiverService;
import com.yami.shop.service.SysConfigService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringEscapeUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 统一支付工具
 *
 * @author LGH
 */
@Service
@AllArgsConstructor
public class PayManager {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final  AliPayConfig aliPayConfig;

    private final  ShopConfig shopConfig;

    private final  WxConfig wxConfig;

    private final  PayPalConfig payPalConfig;

    private final  HnaPayConfig hnaPayConfig;

    private final  ApplicationContext applicationContext;

    private final  SysConfigService sysConfigService;

    private final  PayInfoMapper payInfoMapper;

    private final  RequestKitBean requestKitBean;

    private final PayOrderDivisionRecordService payOrderDivisionRecordService;

    private final ShopDivisionReceiverService shopDivisionReceiverService;

    private static final String WX_SUCCESS_XML = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
    private static final String ALI_SUCCESS = "success";
    private static final String XS_SUCCESS = "200";
    private static final String SUCCESS = "SUCCESS";
    private static final String TRADE_STATUS = "trade_status";
    private static final String TRADE_SUCCESS = "TRADE_SUCCESS";
    private static final String REFUND_FEE = "refund_fee";
    private static final String TRADE_CLOSED = "TRADE_CLOSED";

    public ServerResponseEntity<?> doPay(HttpServletResponse httpResponse, PayInfoDto payInfo) throws WxPayException, AlipayApiException {
        if (payInfo.getPayAmount() < Constant.MIN_PRODUCT_AMOUNT && Objects.equals(payInfo.getPayType(), PayType.SCOREPAY.value())) {
            return ServerResponseEntity.success();
        }
        // 微信支付不能大于1000w
        if (payInfo.getPayAmount() < Constant.MIN_PRODUCT_AMOUNT || payInfo.getPayAmount() > Constant.WECHAT_MAX_PAY_AMOUNT) {
            // 订单金额有误，无法进行支付
            throw new YamiShopBindException("yami.order.amount.error");
        } else if (payInfo.getPayAmount() > Constant.WECHAT_MAX_PAY_AMOUNT) {
            throw new YamiShopBindException("yami.order.amount.too.large.error");
        }
        SysPayConfig sysPayConfig = sysConfigService.getSysConfigObject(Constant.PAY_SWITCH_CONFIG, SysPayConfig.class);
        String domainName = shopConfig.getDomain().getApiDomainName();
        // 如果是商家端需要回调，则使用商家端的地址
        if (Objects.nonNull(payInfo.getBackType()) && Objects.equals(payInfo.getBackType(), BackType.SHOP.value())) {
            domainName = shopConfig.getDomain().getMultishopDomainName();
        }
        String notifyUrl = domainName + payInfo.getApiNoticeUrl();

        PayType payType = PayType.instance(payInfo.getPayType());
        if (PayType.isWxPay(payType)) {
            if (!sysPayConfig.getWxPaySwitch()) {
                throw new YamiShopBindException("yami.order.pay.type.check");
            }
            Integer wxPayVersion = shopConfig.getWxPay().getVersion();
            // v3需要的配置
            if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                return doWxPayV3(payInfo, notifyUrl, payType);
            } else {
                return doWxPay(payInfo, notifyUrl, payType);
            }
        } else if (PayType.isAliPay(payType)) {
            return doAliPay(payInfo, sysPayConfig, notifyUrl, payType);
            // } else if (PayType.isUnionPay(payType)) {
            //     return doUnionPay(payInfo, sysPayConfig, notifyUrl, payType);
        } else if (PayType.isHnaPay(payType)) {
            return doHnaPay(payInfo, sysPayConfig, notifyUrl, payType);
        }
        // 余额支付
        else if (Objects.equals(payType, PayType.BALANCE)) {
            if (!sysPayConfig.getBalancePaySwitch()) {
                throw new YamiShopBindException("yami.order.pay.type.check");
            }
            // 判断如果是余额支付 校验新生渠道必输参数
            payInfo.setReceiveUserId(shopConfig.getHnaPay().getMerId());
            PayInfoParam payInfoParam = new PayInfoParam();
            applicationContext.publishEvent(new BalancePayEvent(payInfo, payInfoParam));
            if (ObjectUtil.isNotNull(payInfoParam.getMessage())) {
                throw new YamiShopBindException(payInfoParam.getMessage());
            }
            return ServerResponseEntity.success(payInfoParam);
        }
        // PayPal支付
        else if (Objects.equals(payType, PayType.PAYPAL)) {
            return doPayPalPay(payInfo, sysPayConfig, notifyUrl);
        }
        // 一般是积分支付才会到这一步
        return ServerResponseEntity.success();
    }

    private ServerResponseEntity<String> doPayPalPay(PayInfoDto payInfoDto, SysPayConfig sysPayConfig, String notifyUrl) {
        if (!sysPayConfig.getPayPalSwitch()) {
            throw new YamiShopBindException("yami.order.pay.type.check");
        }
        payInfoDto.setApiNoticeUrl(notifyUrl);
        OrdersCreateRequest request = payPalConfig.createPayPalOrder(payInfoDto);
        PayPalOrderParam param = payPalConfig.getExcetuteHref(request);
        // 根据支付单号，更新第三方订单号
        PayInfo payInfo = payInfoMapper.selectOne(new LambdaQueryWrapper<PayInfo>().eq(PayInfo::getPayNo, payInfoDto.getPayNo()));
        payInfo.setBizOrderNo(param.getOrderId());
        int updateCount = payInfoMapper.update(payInfo, Wrappers.lambdaUpdate(PayInfo.class).eq(PayInfo::getPayNo, payInfoDto.getPayNo()));
        if (updateCount < 1) {
            // 支付信息更新失败
            throw new YamiShopBindException("yami.shop.pay.info.update.error");
        }
        // 创建钩子，如果已经在paypal配置好钩子可以将下面一行注释掉
        payPalConfig.createWebhook(payInfoDto.getApiNoticeUrl());
        return ServerResponseEntity.success(param.getHref());
    }

    private ServerResponseEntity<?> doWxPay(PayInfoDto payInfo, String notifyUrl, PayType payType) throws WxPayException {
        WxPayService wxPayService = wxConfig.getWxPayService(payType);
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setBody(payInfo.getBody());
        orderRequest.setOutTradeNo(payInfo.getPayNo());
        orderRequest.setTotalFee((int) Arith.mul(payInfo.getPayAmount(), 100));
        orderRequest.setSpbillCreateIp(IPHelper.getIpAddr());
        orderRequest.setOpenid(payInfo.getBizUserId());
        orderRequest.setNotifyUrl(notifyUrl);

        // 微信小程序支付 || 微信公众号支付
        if (Objects.equals(payType, PayType.WECHATPAY) || Objects.equals(payType, PayType.WECHATPAY_MP)) {
            orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
            WxPayMpOrderResult wxPayMpOrderResult = wxPayService.createOrder(orderRequest);
            return ServerResponseEntity.success(wxPayMpOrderResult);
        }
        // 微信网页支付
        else if (Objects.equals(payType, PayType.WECHATPAY_SWEEP_CODE)) {
            orderRequest.setProductId(payInfo.getPayNo());
            // 生成微信二维码
            orderRequest.setTradeType(WxPayConstants.TradeType.NATIVE);
            WxPayNativeOrderResult wxPayNativeOrderResult = wxPayService.createOrder(orderRequest);

            return ServerResponseEntity.success(wxPayNativeOrderResult.getCodeUrl());
        }
        // 微信H5支付
        else if (Objects.equals(payType, PayType.WECHATPAY_H5)) {
            // 生成微信二维码
            orderRequest.setTradeType(WxPayConstants.TradeType.MWEB);
            String s = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"\",\"wap_name\": \"\"}}";
            orderRequest.setSceneInfo(s);
            WxPayMwebOrderResult wxPayMwebOrderResult = wxPayService.createOrder(orderRequest);
            return ServerResponseEntity.success(wxPayMwebOrderResult.getMwebUrl());
        }
        // 微信app支付
        else if (Objects.equals(payType, PayType.WECHATPAY_APP)) {
            orderRequest.setTradeType(WxPayConstants.TradeType.APP);
            WxPayAppOrderResult wxPayAppOrderResult = wxPayService.createOrder(orderRequest);
            return ServerResponseEntity.success(wxPayAppOrderResult);
        }
        return null;
    }

    private ServerResponseEntity<?> doAliPay(PayInfoDto payInfo, SysPayConfig sysPayConfig, String notifyUrl, PayType payType) throws AlipayApiException {
        if (!sysPayConfig.getAliPaySwitch()) {
            throw new YamiShopBindException("yami.order.pay.type.check");
        }
        if (Objects.equals(payType, PayType.ALIPAY)) {
            if (!sysPayConfig.getAliPaySwitch()) {
                throw new YamiShopBindException("yami.order.pay.type.check");
            }
            // 创建API对应的request
            AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();

            // 在公共参数中设置回跳和通知地址
            alipayRequest.setNotifyUrl(notifyUrl);
            alipayRequest.setReturnUrl(payInfo.getReturnUrl());
            AlipayTradePagePayModel alipayTradePagePayModel = new AlipayTradePagePayModel();
            alipayTradePagePayModel.setOutTradeNo(payInfo.getPayNo());
            alipayTradePagePayModel.setBody(payInfo.getBody());
            alipayTradePagePayModel.setSubject(payInfo.getBody());
            alipayTradePagePayModel.setTotalAmount(Double.toString(payInfo.getPayAmount()));
            alipayTradePagePayModel.setProductCode("FAST_INSTANT_TRADE_PAY");
            alipayRequest.setBizModel(alipayTradePagePayModel);

            return ServerResponseEntity.success(aliPayConfig.getAlipayClient().pageExecute(alipayRequest).getBody());
        } else if (Objects.equals(payType, PayType.ALIPAY_H5)) {
            if (!sysPayConfig.getAliPaySwitch()) {
                throw new YamiShopBindException("yami.order.pay.type.check");
            }
            AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
            alipayRequest.setNotifyUrl(notifyUrl);
            alipayRequest.setReturnUrl(payInfo.getReturnUrl());

            AlipayTradeWapPayModel alipayTradeWapPayModel = new AlipayTradeWapPayModel();
            alipayTradeWapPayModel.setOutTradeNo(payInfo.getPayNo());
            alipayTradeWapPayModel.setSubject(payInfo.getBody());
            alipayTradeWapPayModel.setTotalAmount(Double.toString(payInfo.getPayAmount()));
            alipayTradeWapPayModel.setProductCode("QUICK_WAP_PAY");
            alipayRequest.setBizModel(alipayTradeWapPayModel);
            return ServerResponseEntity.success(aliPayConfig.getAlipayClient().pageExecute(alipayRequest).getBody());
        }
        // 支付宝app支付
        else if (Objects.equals(payType, PayType.ALIPAY_APP)) {
            if (!sysPayConfig.getAliPaySwitch()) {
                throw new YamiShopBindException("yami.order.pay.type.check");
            }
            AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest();
            alipayRequest.setNotifyUrl(notifyUrl);
            AlipayTradeAppPayModel alipayTradeAppPayModel = new AlipayTradeAppPayModel();
            alipayTradeAppPayModel.setOutTradeNo(payInfo.getPayNo());
            alipayTradeAppPayModel.setSubject(payInfo.getBody());
            alipayTradeAppPayModel.setTotalAmount(Double.toString(payInfo.getPayAmount()));
            alipayTradeAppPayModel.setProductCode("QUICK_MSECURITY_PAY");
            alipayRequest.setBizModel(alipayTradeAppPayModel);

            String body = aliPayConfig.getAlipayClient().sdkExecute(alipayRequest).getBody();
            return ServerResponseEntity.success(body);
        }
        return null;
    }

    /*private ServerResponseEntity<?> doUnionPay(PayInfoDto payInfo, SysPayConfig sysPayConfig, String notifyUrl, PayType payType) {
        if (!sysPayConfig.getUnionPaySwitch()) {
            throw new YamiShopBindException("yami.order.pay.type.check");
        }
        UnionPay unionPay = shopConfig.getUnionPay();

        // 云闪付-扫码支付
        if (Objects.equals(payType, PayType.UNION_NATIVE)) {
            Map<String, String> params = UnifiedOrderModel.builder().service(ServiceEnum.NATIVE.toString()).mch_id(unionPay.getMachId()).out_trade_no(payInfo.getPayNo()).body(payInfo.getBody()).attach("聚合支付 SDK").total_fee(String.valueOf(Arith.mul(payInfo.getPayAmount(), 100))).mch_create_ip(IPHelper.getIpAddr()).notify_url(notifyUrl).nonce_str(WxPayKit.generateStr()).build().createSign(unionPay.getKey(), SignType.MD5);
            logger.info("请求参数params:" + params.toString());
            String xmlResult = UnionPayApi.execution(unionPay.getServerUrl(), params);
            logger.info("xmlResult:" + xmlResult);
            Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
            return ServerResponseEntity.success(result);
        }
        // 云闪付-微信公众号/小程序支付
        else if (Objects.equals(payType, PayType.UNION_WEI_XIN_MINI_PAY) || Objects.equals(payType, PayType.UNION_WEI_XIN_MP_PAY)) {
            String openId;
            if (Objects.equals(payType, PayType.UNION_WEI_XIN_MINI_PAY)) {
                openId = unionPay.getOpenIdMINI();
            } else {
                openId = unionPay.getOpenIdMP();
            }
            Map<String, String> params = UnifiedOrderModel.builder().service(ServiceEnum.WEI_XIN_JS_PAY.toString()).mch_id(unionPay.getMachId()).is_raw("1").out_trade_no(payInfo.getPayNo()).body(payInfo.getBody())
                    // 当发起公众号支付时，值是微信公众平台基本配置中的AppID(应用ID)；当发起小程序支付时，值是对应小程序的AppID
                    .sub_openid(openId).attach("聚合支付 SDK").total_fee(String.valueOf(Arith.mul(payInfo.getPayAmount(), 100))).mch_create_ip(IPHelper.getIpAddr()).notify_url(notifyUrl).nonce_str(WxPayKit.generateStr()).build().createSign(unionPay.getKey(), SignType.MD5);
            logger.info("请求参数params:" + params.toString());
            String xmlResult = UnionPayApi.execution(unionPay.getServerUrl(), params);
            logger.info("xmlResult:" + xmlResult);
            Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
            return ServerResponseEntity.success(result);
        }
        // 云闪付-微信 App 支付
        else if (Objects.equals(payType, PayType.UNION_WEI_XIN_APP_PAY)) {
            Map<String, String> params = UnifiedOrderModel.builder().service(ServiceEnum.WEI_XIN_APP_PAY.toString()).mch_id(unionPay.getMachId()).appid(unionPay.getAppId()).out_trade_no(payInfo.getPayNo()).body(payInfo.getBody()).attach("聚合支付 SDK").total_fee(String.valueOf(Arith.mul(payInfo.getPayAmount(), 100))).mch_create_ip(IPHelper.getIpAddr()).notify_url(notifyUrl).nonce_str(WxPayKit.generateStr()).build().createSign(unionPay.getKey(), SignType.MD5);
            logger.info("请求参数params:" + params.toString());
            String xmlResult = UnionPayApi.execution(unionPay.getServerUrl(), params);
            logger.info("xmlResult:" + xmlResult);
            Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
            if (!WxPayKit.verifyNotify(result, unionPay.getKey(), SignType.MD5)) {
                throw new YamiShopBindException("yami.sign.check");
            }
            return ServerResponseEntity.success(result);
        }
        // 云闪付-支付宝服务窗口
        else if (Objects.equals(payType, PayType.UNION_ALI_PAY_JS_PAY)) {
            Map<String, String> params = UnifiedOrderModel.builder().service(ServiceEnum.ALI_PAY_JS_PAY.toString()).mch_id(unionPay.getMachId()).out_trade_no(payInfo.getPayNo()).body(payInfo.getBody()).attach("聚合支付 SDK").total_fee(String.valueOf(Arith.mul(payInfo.getPayAmount(), 100))).mch_create_ip(IPHelper.getIpAddr()).notify_url(notifyUrl).nonce_str(WxPayKit.generateStr())
                    // 买家支付宝用户ID，和buyer_logon_id不能同时为空
                    // buyer_id获取方法：https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.8ujLD6&treeId=115&articleId=104114&docType=1通过网页授权获取用户信息，同步响应结果中的user_id对应文档中的
                    .buyer_id(payInfo.getBuyerId()).build().createSign(unionPay.getKey(), SignType.MD5);
            logger.info("请求参数params:" + params.toString());
            String xmlResult = UnionPayApi.execution(unionPay.getServerUrl(), params);
            logger.info("xmlResult:" + xmlResult);
            Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
            return ServerResponseEntity.success(result);
        }
        // 云闪付-银联JS支付
        else if (Objects.equals(payType, PayType.UNION_JS_PAY)) {
            Map<String, String> params = UnifiedOrderModel.builder().service(ServiceEnum.UNION_JS_PAY.toString()).mch_id(unionPay.getMachId()).out_trade_no(WxPayKit.generateStr()).body(payInfo.getBody()).user_id(payInfo.getUniUserId()).customer_ip(IPHelper.getIpAddr()).attach("聚合支付 SDK").total_fee(String.valueOf(Arith.mul(payInfo.getPayAmount(), 100))).mch_create_ip(IPHelper.getIpAddr()).notify_url(notifyUrl).nonce_str(WxPayKit.generateStr()).build().createSign(unionPay.getKey(), SignType.MD5);
            logger.info("请求参数params:" + params.toString());
            String xmlResult = UnionPayApi.execution(unionPay.getServerUrl(), params);
            logger.info("xmlResult:" + xmlResult);
            Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
            return ServerResponseEntity.success(result);
        }
        return null;
    }*/

    private ServerResponseEntity<?> doHnaPay(PayInfoDto payInfo, SysPayConfig sysPayConfig, String notifyUrl, PayType payType) {
        if (!sysPayConfig.getHnaPaySwitch()) {
            throw new YamiShopBindException("yami.order.pay.type.check");
        }
        BaseTransForm base;
        // 新生支付-支付宝H5支付/云闪付H5支付
        if (Objects.equals(payType, PayType.HNAPAY_ALI_PAY_H5) || Objects.equals(payType, PayType.HNAPAY_YSF_PAY_H5)) {
            try {
                base = hnaPayConfig.getT013TransForm(payInfo, notifyUrl);
                logger.info("调用新生接口请求参数为："+JSONUtil.toJsonStr(base));
                Map<String, Object> responseMap = hnaPayConfig.post(base);
                logger.info("调用新生接口响应参数为："+JSONUtil.toJsonStr(responseMap));
                // 保存分账信息
                processPayOrderDivision(payInfo);
                return ServerResponseEntity.success(responseMap);
            } catch (Exception e) {
                return ServerResponseEntity.showFailMsg(e.getMessage());
            }
        }
        // 新生支付-支付宝生活号支付/微信公众号支付
        else if (Objects.equals(payType, PayType.HNAPAY_ALI_PAY_JS_PAY) || Objects.equals(payType, PayType.HNAPAY_WECHAT_PAY_JS_PAY)) {
            try {
                base = hnaPayConfig.getT006TransForm(payInfo, notifyUrl);
                Map<String, Object> responseMap = hnaPayConfig.post(base);
                // 保存分账信息
                processPayOrderDivision(payInfo);
                return ServerResponseEntity.success(responseMap);
            } catch (Exception e) {
                return ServerResponseEntity.showFailMsg(e.getMessage());
            }
        }
        // 新生支付-快捷支付下单
        else if (Objects.equals(payType, PayType.HNAPAY_KJ)) {
            base = hnaPayConfig.getT007TransForm(payInfo, notifyUrl);
            try {
                Map<String, Object> responseMap = hnaPayConfig.post(base);
                responseMap.put("payNo", payInfo.getPayNo());
                return ServerResponseEntity.success(responseMap);
            } catch (Exception e) {
                return ServerResponseEntity.showFailMsg(e.getMessage());
            }
        }
        return null;
    }

    private ServerResponseEntity<?> doWxPayV3(PayInfoDto payInfo, String notifyUrl, PayType payType) throws WxPayException {
        WxPayService wxPayService = wxConfig.getWxPayService(payType);
        WxPayUnifiedOrderV3Request orderRequest = new WxPayUnifiedOrderV3Request();
        orderRequest.setDescription(payInfo.getBody());
        orderRequest.setOutTradeNo(payInfo.getPayNo());
        orderRequest.setNotifyUrl(notifyUrl);
        orderRequest.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal((int) Arith.mul(payInfo.getPayAmount(), 100)));
        orderRequest.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(payInfo.getBizUserId()));

        // 微信小程序支付 || 微信公众号支付
        if (Objects.equals(payType, PayType.WECHATPAY) || Objects.equals(payType, PayType.WECHATPAY_MP)) {
            return ServerResponseEntity.success(wxPayService.createOrderV3(TradeTypeEnum.JSAPI, orderRequest));
        }
        // 微信网页支付
        else if (Objects.equals(payType, PayType.WECHATPAY_SWEEP_CODE)) {
            // 生成微信二维码
            return ServerResponseEntity.success(wxPayService.createOrderV3(TradeTypeEnum.NATIVE, orderRequest));
        }
        // 微信H5支付
        else if (Objects.equals(payType, PayType.WECHATPAY_H5)) {
            orderRequest.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(IPHelper.getIpAddr()).setH5Info(new WxPayUnifiedOrderV3Request.H5Info().setType("Wap")));
            // 生成h5支付地址
            return ServerResponseEntity.success(wxPayService.createOrderV3(TradeTypeEnum.H5, orderRequest));
        }
        // 微信app支付
        else if (Objects.equals(payType, PayType.WECHATPAY_APP)) {
            return ServerResponseEntity.success(wxPayService.createOrderV3(TradeTypeEnum.APP, orderRequest));
        }
        return null;
    }

    /**
     * 新生快捷支付第二步，支付确认
     */
    public ServerResponseEntity<?> doHnaPayKjSen(PayXsCountOrderParam payXsCountOrderParam,PayInfo payInfo) {
        try {
            BaseTransForm base = hnaPayConfig.getT008TransForm(payXsCountOrderParam);
            Map<String, Object> responseMap = hnaPayConfig.post(base);
            // 保存分账信息
            PayInfoDto payInfoDto = new PayInfoDto();
            payInfoDto.setPayNo(payInfo.getPayNo());
            payInfoDto.setPayAmount(payInfo.getPayAmount());
            payInfoDto.setBusinessType(payXsCountOrderParam.getBusinessType());
            payInfoDto.setReceiverGroupId(payXsCountOrderParam.getReceiverGroupId());
            payInfoDto.setDivideAcctDtlList(payXsCountOrderParam.getDivideAcctDtlList());
            processPayOrderDivision(payInfoDto);
            return ServerResponseEntity.success(responseMap);
        } catch (Exception e) {
            return ServerResponseEntity.showFailMsg(e.getMessage());
        }
    }

    /**
     * 校验支付结果，并返回支付单号
     */
    public PayInfoResultBO validateAndGetPayInfo(HttpServletRequest request, PayType payType, String data) throws UnsupportedEncodingException, WxPayException, AlipayApiException {

        PayInfoResultBO payInfoResultBO = new PayInfoResultBO();

        if (PayType.isWxPay(payType)) {
            WxPayService wxPayService = wxConfig.getWxPayService(payType);
            Integer wxPayVersion = shopConfig.getWxPay().getVersion();
            // v3需要的配置
            if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                WxPayOrderNotifyV3Result wxPayOrderNotifyV3Result = wxPayService.parseOrderNotifyV3Result(data, getSignatureHeader(request));
                payInfoResultBO.setPayNo(wxPayOrderNotifyV3Result.getResult().getOutTradeNo());
                payInfoResultBO.setBizPayNo(wxPayOrderNotifyV3Result.getResult().getTransactionId());
                payInfoResultBO.setIsPaySuccess(SUCCESS.equals(wxPayOrderNotifyV3Result.getResult().getTradeState()));
                // 返回200就行，无需内容
//                payInfoResultBO.setSuccessString();
                payInfoResultBO.setPayAmount(Arith.div(wxPayOrderNotifyV3Result.getResult().getAmount().getTotal(), 100));
                payInfoResultBO.setCallbackContent(data);
            } else {
                WxPayOrderNotifyResult parseOrderNotifyResult = wxPayService.parseOrderNotifyResult(data);
                payInfoResultBO.setPayNo(parseOrderNotifyResult.getOutTradeNo());
                payInfoResultBO.setBizPayNo(parseOrderNotifyResult.getTransactionId());
                payInfoResultBO.setIsPaySuccess(SUCCESS.equals(parseOrderNotifyResult.getResultCode()));
                payInfoResultBO.setSuccessString(WX_SUCCESS_XML);
                payInfoResultBO.setPayAmount(Arith.div(parseOrderNotifyResult.getTotalFee(), 100));
                payInfoResultBO.setCallbackContent(data);
            }

        } else if (PayType.isAliPay(payType)) {
            // 获取支付宝POST过来反馈信息
            Map<String, String> params = parseAliNotifyAndGetResult(request);

            if (Objects.equals(params.get(TRADE_STATUS), TRADE_SUCCESS)) {
                // 商户订单号,之前生成的带用户ID的订单号
                payInfoResultBO.setPayNo(params.get("out_trade_no"));
                // 支付宝交易号
                payInfoResultBO.setBizPayNo(params.get("trade_no"));
                payInfoResultBO.setIsPaySuccess(true);
                payInfoResultBO.setSuccessString(ALI_SUCCESS);
                payInfoResultBO.setPayAmount(new BigDecimal(params.get("total_amount")).doubleValue());
                // 这个是支付宝退款的通知
                if (StrUtil.isNotBlank(params.get(REFUND_FEE))) {
                    payInfoResultBO.setIsPaySuccess(false);
                }
            } else {
                payInfoResultBO.setIsPaySuccess(false);
            }
            payInfoResultBO.setCallbackContent(Json.toJsonString(params));

        } else if (Objects.equals(payType, PayType.PAYPAL)) {
            // webhook 回调
            Map<String, String> headers = payPalConfig.getHeadersInfo(request);
            WebhookParam webhookParam = JSON.parseObject(data, WebhookParam.class);
            boolean isVerify = payPalConfig.verifyWebhookSign(request, headers, data);
            if (!isVerify) {
                // 验签失败
                throw new YamiShopBindException("yami.sign.check");
            }
            String bizOrderNo = webhookParam.getResource().getId();
            if (StrUtil.isNotBlank(bizOrderNo)) {
                // 查询是否支付完成如果系统订单是已经支付完成就退款
                PayInfo payInfo = payInfoMapper.selectOne(Wrappers.lambdaQuery(PayInfo.class).eq(PayInfo::getBizOrderNo, bizOrderNo).last("limit 1"));
                if (Objects.isNull(payInfo)) {
                    // 找不到支付记录
                    throw new YamiShopBindException("找不到支付记录" + data);
                }
                if (Objects.equals(PayStatus.PAYED.value(), payInfo.getPayStatus())) {
                    // 已支付完成,支付失败，订单不在未支付状态
                    throw new YamiShopBindException("yami.order.pay.fail");
                }
                // 执行扣款操作
                payInfoResultBO = payPalConfig.captureOrder(bizOrderNo);
            } else {
                payInfoResultBO.setIsPaySuccess(false);
            }
            payInfoResultBO.setCallbackContent(data);
        }
        /*else if (PayType.isUnionPay(payType)) {
            UnionPay unionPay = shopConfig.getUnionPay();
            String xmlMsg = HttpKit.readData(request);
            logger.info("银联支付通知=" + xmlMsg);
            Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
            String status = params.get("status");
            String returnCode = params.get("result_code");
            logger.info(status + " " + returnCode);
            if ("0".equals(status) && "0".equals(returnCode)) {
                // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
                // 注意此处签名方式需与统一下单的签名类型一致
                if (!WxPayKit.verifyNotify(params, unionPay.getKey(), SignType.MD5)) {
                    // 验签失败
                    throw new YamiShopBindException("yami.sign.check");
                }
                if ("0".equals(params.get("pay_result"))) {
                    // 支付成功
                    payInfoResultBO.setPayNo(params.get("out_trade_no"));
                    // 支付宝交易号
                    payInfoResultBO.setBizPayNo(params.get("transaction_id"));
                    payInfoResultBO.setIsPaySuccess(true);
                    payInfoResultBO.setSuccessString(ALI_SUCCESS);
                    BigDecimal total_fee = new BigDecimal(params.get("total_fee")).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_HALF_UP);
                    payInfoResultBO.setPayAmount(total_fee.doubleValue());
                } else {
                    payInfoResultBO.setIsPaySuccess(false);
                }

            } else {
                payInfoResultBO.setIsPaySuccess(false);
            }
            payInfoResultBO.setCallbackContent(data);
        } */
        else if (PayType.isHnaPay(payType)) {
            JSONObject params = requestKitBean.getReqParamJSON();
            logger.info("新生支付回调参数, jsonParams" + JSONUtil.toJsonStr(params));
            // 判断上游订单状态
            if (ObjectUtil.isNotEmpty(params) && params.getString("resultCode").equals("0000")) {
                // 支付成功
                payInfoResultBO.setPayNo(params.get("merOrderId").toString().substring(0,params.get("merOrderId").toString().length()-2));
                // 支付交易号
                payInfoResultBO.setBizPayNo(params.get("ncountOrderId").toString());
                payInfoResultBO.setBizOrderNo(params.get("merOrderId").toString());
                payInfoResultBO.setIsPaySuccess(true);
                payInfoResultBO.setSuccessString(XS_SUCCESS);
                payInfoResultBO.setPayAmount(new BigDecimal(params.get("tranAmount").toString()).doubleValue());
                payInfoResultBO.setDivideAcctDtl(params.get("divideAcctDtl").toString());
            } else {
                payInfoResultBO.setIsPaySuccess(false);
            }
            payInfoResultBO.setCallbackContent(data);
        }

        if (StrUtil.isNotBlank(payInfoResultBO.getCallbackContent())) {
            PayInfo payInfo = new PayInfo();
            payInfo.setPayNo(payInfoResultBO.getPayNo());
            payInfo.setBizPayNo(payInfoResultBO.getBizPayNo());
            payInfo.setBizOrderNo(payInfoResultBO.getBizOrderNo());
            payInfo.setCallbackTime(new Date());
            String divideAcctDtlStr = payInfoResultBO.getDivideAcctDtl();
            if(StringUtils.isNotEmpty(divideAcctDtlStr)){
                String divideAcctDtl = StringEscapeUtils.unescapeJava(divideAcctDtlStr);
                JSONArray jsona = (JSONArray) JSONArray.parse(divideAcctDtl);
                JSONObject jsonObject = jsona.getJSONObject(0);
                if (ObjectUtil.isNotEmpty(jsonObject.getString("divideId"))) {
                    String divideId = jsonObject.getString("divideId");
                    payInfo.setDivideId(divideId);
                    payInfo.setDivideStatus(DivideStatus.CONFIRM.value().toString());
                }
            }
            payInfo.setDivideAcctDtl(payInfoResultBO.getDivideAcctDtl());
            payInfo.setCallbackContent(payInfoResultBO.getCallbackContent());
            // 支付宝多次回调可能该支付单已经退款，但还是更新了回调时间导致对账查询有误
            payInfoMapper.update(payInfo, new LambdaUpdateWrapper<PayInfo>().eq(PayInfo::getPayNo, payInfo.getPayNo()).eq(PayInfo::getPayStatus, PayStatus.UNPAY.value()));
        }
        return payInfoResultBO;
    }

    @NotNull
    private SignatureHeader getSignatureHeader(HttpServletRequest request) {
        SignatureHeader signatureHeader = new SignatureHeader();
        signatureHeader.setSignature(request.getHeader("Wechatpay-Signature"));
        signatureHeader.setNonce(request.getHeader("Wechatpay-Nonce"));
        signatureHeader.setTimeStamp(request.getHeader("Wechatpay-TimeStamp"));
        signatureHeader.setSerial(request.getHeader("Wechatpay-Serial"));
        return signatureHeader;
    }

    /**
     * 退款
     *
     * @param refundInfo refundInfo
     * @return boolean
     */
    public boolean doRefund(RefundInfoDto refundInfo) {

        PayType payType = refundInfo.getPayType();
        if (Objects.equals(refundInfo.getRefundAmount(), 0.0)) {
            return true;
        }
        Domain domain = shopConfig.getDomain();
        // 提交提款操作
        try {
            if (PayType.isWxPay(payType)) {
                // 订单金额
                double totalFee = Arith.mul(refundInfo.getPayAmount(), 100);
                // 退款金额
                double refundFee = Arith.mul(refundInfo.getRefundAmount(), 100);
                WxPayService wxPayService = wxConfig.getWxPayService(payType);
                Integer wxPayVersion = shopConfig.getWxPay().getVersion();
                if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                    WxPayRefundV3Request wxPayRefundV3Request = new WxPayRefundV3Request();
                    wxPayRefundV3Request.setOutTradeNo(refundInfo.getPayNo());
                    wxPayRefundV3Request.setAmount(new WxPayRefundV3Request.Amount().setTotal((int) totalFee).setRefund((int) refundFee).setCurrency("CNY"));
                    wxPayRefundV3Request.setOutRefundNo(refundInfo.getRefundSn());
                    // notifyUrl（通知结果）
                    if (!Objects.equals(refundInfo.getOnlyRefund(), 1)) {
                        // 只进行退款，不需要任何回调
                        wxPayRefundV3Request.setNotifyUrl(domain.getMultishopDomainName() + refundInfo.getNotifyUrl());
                    }
                    wxPayService.refundV3(wxPayRefundV3Request);
                } else {
                    // 退款操作
                    // 生成退款请求对象
                    WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
                    // 商户订单号
                    wxPayRefundRequest.setOutTradeNo(refundInfo.getPayNo());
                    wxPayRefundRequest.setTotalFee((int) totalFee);
                    wxPayRefundRequest.setRefundFee((int) refundFee);
                    // 退款编码
                    wxPayRefundRequest.setOutRefundNo(refundInfo.getRefundSn());

                    // notifyUrl（通知结果）
                    if (!Objects.equals(refundInfo.getOnlyRefund(), 1)) {
                        // 只进行退款，不需要任何回调
                        wxPayRefundRequest.setNotifyUrl(domain.getMultishopDomainName() + refundInfo.getNotifyUrl());
                    }
                    wxPayService.refund(wxPayRefundRequest);
                }

            } else if (PayType.isAliPay(payType)) {
                AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
                request.setNotifyUrl(domain.getMultishopDomainName() + refundInfo.getNotifyUrl());
                AlipayTradeRefundModel alipayTradeRefundModel = new AlipayTradeRefundModel();
                alipayTradeRefundModel.setOutTradeNo(refundInfo.getPayNo());
                alipayTradeRefundModel.setOutRequestNo(refundInfo.getRefundSn());
                alipayTradeRefundModel.setRefundAmount(Double.toString(refundInfo.getRefundAmount()));
                request.setBizModel(alipayTradeRefundModel);
                AlipayTradeRefundResponse response = aliPayConfig.getAlipayClient().certificateExecute(request);
                // 对fund_change必须了解为本次退款操作，若相同退款参数调用，第一次返回fund_change=Y，第二次返回fund_change=N，但是第二次仍返回退款信息。
                if (response.isSuccess() && StrUtil.isNotBlank(response.getFundChange())) {
                    return true;
                }
            } else if (Objects.equals(payType, PayType.BALANCE)) {
                applicationContext.publishEvent(new BalanceRefundEvent(refundInfo));
            } else if (Objects.equals(payType, PayType.PAYPAL)) {
                // payPal申请退款
                return payPalConfig.refundOrder(refundInfo);
           /* } else if (PayType.isUnionPay(payType)) {
                // unionPay申请退款
                return payPalConfig.unionPayRefundOrder(refundInfo);*/
            } else if (PayType.isHnaPay(payType)) {
                // 新生支付申请退款
                PayInfo payInfo = payInfoMapper.selectOne(Wrappers.lambdaQuery(PayInfo.class).eq(PayInfo::getBizPayNo, refundInfo.getBizPayNo()).last("limit 1"));
                return hnaPayConfig.hnaPayRefundOrder(refundInfo, payInfo);
            }
        } catch (WxPayException e) {
            logger.error("微信退款发生错误：", e);
            throw new YamiShopBindException(e.getCustomErrorMsg(), e);
        } catch (AlipayApiException e) {
            logger.error("阿里退款发生错误：", e);
            throw new YamiShopBindException(e.getErrMsg(), e);
        } catch (Exception e) {
            logger.error("退款发生错误：", e);
            throw new YamiShopBindException(e.getMessage(), e);
        }
        return false;
    }

    /**
     * 退款回调处理，并返回支付单号
     *
     * @param request request
     * @param payType payType
     * @param data data
     * @return RefundInfoBo
     * @throws UnsupportedEncodingException UnsupportedEncodingException
     * @throws WxPayException WxPayException
     * @throws AlipayApiException AlipayApiException
     */
    public RefundInfoBo validateAndGetRefundInfo(HttpServletRequest request, PayType payType, String data) throws UnsupportedEncodingException, WxPayException, AlipayApiException {

        RefundInfoBo refundInfoBo = new RefundInfoBo();
        refundInfoBo.setIsRefundSuccess(false);

        if (PayType.isWxPay(payType)) {
            Integer wxPayVersion = shopConfig.getWxPay().getVersion();
            WxPayService wxPayService = wxConfig.getWxPayService(payType);
            if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                WxPayRefundNotifyV3Result wxPayRefundNotifyV3Result = wxPayService.parseRefundNotifyV3Result(data, getSignatureHeader(request));
                WxPayRefundNotifyV3Result.DecryptNotifyResult result = wxPayRefundNotifyV3Result.getResult();
                if (Constant.SUCCESS.equals(result.getRefundStatus())) {
                    refundInfoBo.setIsRefundSuccess(true);
                    refundInfoBo.setSuccessString(WX_SUCCESS_XML);
                    refundInfoBo.setRefundNo(result.getOutRefundNo());
                    refundInfoBo.setBizRefundNo(result.getRefundId());
                    refundInfoBo.setCallbackContent(data);
                }
            } else {
                WxPayRefundNotifyResult wxPayRefundNotifyResult = wxPayService.parseRefundNotifyResult(data);
                WxPayRefundNotifyResult.ReqInfo reqInfo = wxPayRefundNotifyResult.getReqInfo();
                if (Constant.SUCCESS.equals(reqInfo.getRefundStatus())) {
                    refundInfoBo.setIsRefundSuccess(true);
                    refundInfoBo.setSuccessString(WX_SUCCESS_XML);
                    refundInfoBo.setRefundNo(reqInfo.getOutRefundNo());
                    refundInfoBo.setBizRefundNo(reqInfo.getRefundId());
                    refundInfoBo.setCallbackContent(data);
                }
            }
        } else if (PayType.isAliPay(payType)) {
            Map<String, String> params = parseAliNotifyAndGetResult(request);
            if (Objects.equals(params.get(TRADE_STATUS), TRADE_SUCCESS) || Objects.equals(params.get(TRADE_STATUS), TRADE_CLOSED)) {
                refundInfoBo.setIsRefundSuccess(true);
                refundInfoBo.setRefundNo(params.get("out_biz_no"));
                refundInfoBo.setBizRefundNo("");
                refundInfoBo.setSuccessString(ALI_SUCCESS);
                refundInfoBo.setCallbackContent(Json.toJsonString(params));
            }
        } else if (PayType.isHnaPay(payType)) {
            JSONObject params = requestKitBean.getReqParamJSON();
            logger.info("新生支付退款回调参数, jsonParams" + JSONUtil.toJsonStr(params));
            if (ObjectUtil.isNotEmpty(params) && params.getString("resultCode").equals("0000")) {
                refundInfoBo.setIsRefundSuccess(true);
                refundInfoBo.setRefundNo(params.get("orgMerOrderId").toString());
                refundInfoBo.setBizRefundNo(params.get("ncountOrderId").toString());
                refundInfoBo.setSuccessString(XS_SUCCESS);
                refundInfoBo.setCallbackContent(params.toJSONString());
            }
        }
        return refundInfoBo;
    }

    /**
     * 支付查询
     */
    public PayInfoResultBO getPayInfo(PayType payType, String payNo, String bizPayNo) {
        Integer wxPayVersion = shopConfig.getWxPay().getVersion();
        PayInfoResultBO payInfo = new PayInfoResultBO();
        payInfo.setPayNo(payNo);
        payInfo.setBizPayNo(bizPayNo);
        try {
            if (PayType.isWxPay(payType)) {
                WxPayService wxPayService = wxConfig.getWxPayService(payType);
                // v3需要的配置
                if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                    WxPayOrderQueryV3Result wxPayOrderQueryV3Result = wxPayService.queryOrderV3(null, payNo);
                    if (!Objects.isNull(wxPayOrderQueryV3Result) && Objects.equals(wxPayOrderQueryV3Result.getTradeState(), Constant.SUCCESS)) {
                        payInfo.setBizPayNo(wxPayOrderQueryV3Result.getTransactionId());
                        payInfo.setIsPaySuccess(true);
                    } else {
                        payInfo.setIsPaySuccess(false);
                    }
                } else {
                    WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder(null, payNo);
                    if (!Objects.isNull(wxPayOrderQueryResult) && Objects.equals(wxPayOrderQueryResult.getTradeState(), Constant.SUCCESS)) {
                        payInfo.setBizPayNo(wxPayOrderQueryResult.getTransactionId());
                        payInfo.setIsPaySuccess(true);
                    } else {
                        payInfo.setIsPaySuccess(false);
                    }
                }
            } else if (PayType.isAliPay(payType)) {
                AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
                AlipayTradeQueryModel alipayTradeQueryModel = new AlipayTradeQueryModel();
                alipayTradeQueryModel.setOutTradeNo(payNo);

                request.setBizModel(alipayTradeQueryModel);
                AlipayTradeQueryResponse response = aliPayConfig.getAlipayClient().certificateExecute(request);
                if (response.isSuccess()) {
                    payInfo.setBizPayNo(response.getTradeNo());
                    payInfo.setIsPaySuccess(true);
                } else {
                    payInfo.setIsPaySuccess(false);
                }
            } else if (Objects.equals(payType, PayType.PAYPAL)) {
                // paypal查单
                if (Objects.isNull(bizPayNo)) {
                    payInfo.setIsPaySuccess(false);
                    return payInfo;
                }
                payPalConfig.getCapture(payInfo);
          /*  } else if (PayType.isUnionPay(payType)) {
                Map<String, String> params = OrderQueryModel.builder().service(ServiceEnum.QUERY.toString()).mch_id(shopConfig.getUnionPay().getMachId()).out_trade_no(payNo).transaction_id(bizPayNo).nonce_str(WxPayKit.generateStr()).build().createSign(shopConfig.getUnionPay().getKey(), SignType.MD5);

                String xmlResult = UnionPayApi.execution(shopConfig.getUnionPay().getServerUrl(), params);
                logger.info("xmlResult:" + xmlResult);
                Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
                if (!WxPayKit.verifyNotify(result, shopConfig.getUnionPay().getKey(), SignType.MD5)) {
                    throw new YamiShopBindException("yami.sign.check");
                }
                String status = params.get("status");
                String returnCode = params.get("result_code");
                if ("0".equals(status) && "0".equals(returnCode)) {
                    if ("SUCCESS".equals(params.get("trade_state"))) {
                        payInfo.setBizPayNo(params.get("transaction_id"));
                        payInfo.setIsPaySuccess(true);
                    } else {
                        payInfo.setIsPaySuccess(false);
                    }
                } else {
                    payInfo.setIsPaySuccess(false);
                }*/
            } else if (PayType.isHnaPay(payType)) {
                BaseTransForm base = hnaPayConfig.getQ002TransForm(payInfo);
                try {
                    Map<String, Object> responseMap = hnaPayConfig.post(base);
                    String respCode = responseMap.get("resultCode").toString();
                    if (respCode.equals("0000")) {
                        // 0：进行中 1：成功 2：失败 3：失效
                        if (responseMap.get("orderStatus").toString().equals("1")) {
                            // 交易成功
                            payInfo.setBizPayNo(responseMap.get("ncountOrderId").toString());
                            payInfo.setIsPaySuccess(true);
                        } else {
                            payInfo.setIsPaySuccess(false);
                        }
                    }
                } catch (Exception e) {
                    logger.error("查询新生支付信息错误：", e);
                }
            } else {
                payInfo.setIsPaySuccess(false);
            }
        } catch (WxPayException | AlipayApiException e) {
            logger.error("获取支付信息错误：", e);
            payInfo.setIsPaySuccess(false);
        }
        return payInfo;
    }

    /**
     * 二维码支付取消
     */
    public Boolean cancelOrderQrCode(List<PayInfo> payInfoList) throws WxPayException, AlipayApiException {
        Integer wxPayVersion = shopConfig.getWxPay().getVersion();
        Map<Integer, List<PayInfo>> payTypeMap = payInfoList.stream().collect(Collectors.groupingBy(PayInfo::getPayType));
        for (Integer payType : payTypeMap.keySet()) {
            PayType type = PayType.instance(payType);
            List<PayInfo> infoList = payTypeMap.get(payType);
            for (PayInfo payInfo : infoList) {
                if (PayType.isWxPay(type)) {
                    WxPayService wxPayService = wxConfig.getWxPayService(type);
                    // v3需要的配置
                    if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                        wxPayService.closeOrderV3(payInfo.getPayNo());
                    } else {
                        wxPayService.closeOrder(payInfo.getPayNo());
                    }
                } else if (PayType.isAliPay(type)) {
                    AlipayTradeCloseRequest tradeCloseRequest = new AlipayTradeCloseRequest();
                    AlipayTradeCloseModel tradeCloseModel = new AlipayTradeCloseModel();
                    tradeCloseModel.setOutTradeNo(payInfo.getPayNo());
                    tradeCloseRequest.setBizModel(tradeCloseModel);
                    AlipayTradeCloseResponse response = aliPayConfig.getAlipayClient().certificateExecute(tradeCloseRequest);
                    logger.warn(response.getBody());
                    if (!response.isSuccess()) {
                        return false;
                    }
                /*} else if (PayType.isUnionPay(type)) {
                    if (Objects.equals(payType, PayType.UNION_NATIVE)) {
                        Map<String, String> params = CloseOrderModel.builder().service(ServiceEnum.CLOSE.toString()).mch_id(shopConfig.getUnionPay().getMachId()).out_trade_no(payInfo.getPayNo()).nonce_str(WxPayKit.generateStr()).build().createSign(shopConfig.getUnionPay().getKey(), SignType.MD5);
                        logger.info("请求参数params:" + params.toString());
                        String xmlResult = UnionPayApi.execution(shopConfig.getUnionPay().getServerUrl(), params);
                        logger.info("xmlResult:" + xmlResult);
                        String status = params.get("status");
                        String returnCode = params.get("result_code");
                        if (!"0".equals(status) || !"0".equals(returnCode)) {
                            return false;
                        }
                    }*/
                }
            }
        }
        return true;
    }

    /**
     * 获取支付宝POST过来反馈信息
     *
     * @param request request
     * @return Map
     * @throws UnsupportedEncodingException UnsupportedEncodingException
     * @throws AlipayApiException AlipayApiException
     */
    private Map<String, String> parseAliNotifyAndGetResult(HttpServletRequest request) throws UnsupportedEncodingException, AlipayApiException {
        Map<String, String> params = getRequestParamsMap(request);
        // 调用SDK验证签名
        boolean signVerified = AlipaySignature.rsaCertCheckV1(params, shopConfig.getAlipay().getAlipayCertPath(), cn.hutool.core.util.CharsetUtil.UTF_8, AlipayConstants.SIGN_TYPE_RSA2);

        if (!signVerified) {
            // 验签失败
            throw new YamiShopBindException("yami.sign.check");
        }
        return params;
    }

    /**
     * 获取请求参数
     */
    private Map<String, String> getRequestParamsMap(HttpServletRequest request) throws UnsupportedEncodingException {
        // 乱码解决，这段代码在出现乱码时使用
        request.setCharacterEncoding("utf-8");
        // 获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<>(16);
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        return params;
    }


    /**
     * 保存分账信息
     */
    private void processPayOrderDivision(PayInfoDto payInfo){
        logger.info("保存分账信息开始："+JSONUtil.toJsonStr(payInfo));
        if(payInfo.getBusinessType().equals("04") && ObjectUtil.isNotNull(payInfo.getDivideAcctDtlList()) && ObjectUtil.isNotNull(payInfo.getReceiverGroupId())){

            List<LedgerOrderDto> divideAcctDts = JSONUtil.toList(payInfo.getDivideAcctDtlList(), LedgerOrderDto.class);
            // 所有的分账列表
            List<PayOrderDivisionRecord> recordList = new ArrayList<>();
            // 查询&过滤 所有的分账接收对象
            List<ShopDivisionReceiver> allReceiver = shopDivisionReceiverService.list(
                    new LambdaQueryWrapper<ShopDivisionReceiver>()
                            .eq(ShopDivisionReceiver::getReceiverGroupId, payInfo.getReceiverGroupId())
                            .eq(ShopDivisionReceiver::getState, 1));
            String batchOrderId = SeqKit.genDivisionBatchId();
            Double subDivisionAmount = payInfo.getPayAmount();

            for (ShopDivisionReceiver receiver : allReceiver) {
                logger.info("分账批次号{}",batchOrderId);
                PayOrderDivisionRecord record = genRecord(batchOrderId, payInfo, receiver, payInfo.getPayAmount(), subDivisionAmount);
                //剩余金额
                logger.info("111{}",record.getCalDivisionAmount());
                logger.info("222{}",subDivisionAmount);
                subDivisionAmount = subDivisionAmount - record.getCalDivisionAmount();
                logger.info("剩余金额{}",subDivisionAmount);
                recordList.add(record);
            }
            logger.info("全部分账记录{}",recordList.size());
            if(!recordList.isEmpty()){
                //入库保存
                payOrderDivisionRecordService.saveBatch(recordList);
            }
        }
    }

    /** 生成对象信息 **/
    private PayOrderDivisionRecord genRecord(String batchOrderId, PayInfoDto payInfo, ShopDivisionReceiver receiver,
                                             Double payOrderDivisionAmount, Double subDivisionAmount){
        logger.info("生成分账对象信息开始");
        PayOrderDivisionRecord record = new PayOrderDivisionRecord();
        record.setPayNo(payInfo.getPayNo());
        record.setPayOrderAmount(payInfo.getPayAmount()); //订单金额
        record.setPayOrderDivisionAmount(payOrderDivisionAmount); // 订单计算分账金额
        record.setBatchOrderId(batchOrderId); //系统分账批次号
        record.setState(PayOrderDivisionRecord.STATE_WAIT); //状态: 待分账
        record.setReceiverId(receiver.getReceiverId());
        record.setReceiverGroupId(receiver.getReceiverGroupId());
        record.setReceiverAlias(ObjectUtil.isNotNull(receiver.getReceiverAlias())?receiver.getReceiverAlias() :"" );
        record.setAccType(receiver.getAccType());
        record.setAccNo(receiver.getAccNo());
        record.setAccName(receiver.getAccName());
        record.setRelationType(receiver.getRelationType());
        record.setRelationTypeName(receiver.getRelationTypeName());
        record.setDivisionProfit(receiver.getDivisionProfit());
        record.setCreateTime(new Date());
        record.setUpdateTime(new Date());
        if( subDivisionAmount <= 0 ) {
            record.setCalDivisionAmount(0.0);
        }else{

            //计算的分账金额
            record.setCalDivisionAmount(new BigDecimal(record.getPayOrderDivisionAmount()).multiply(record.getDivisionProfit()).setScale(2, BigDecimal.ROUND_HALF_DOWN).doubleValue());
            if(record.getCalDivisionAmount() > subDivisionAmount){ // 分账金额超过剩余总金额时： 将按照剩余金额进行分账。
                record.setCalDivisionAmount(subDivisionAmount);
            }
        }

        logger.info("生成的分账对象信息{}",JSONUtil.toJsonStr(record));
        return record;
    }


    public static void main(String[] args) {
        double v = new BigDecimal(0.5).multiply(new BigDecimal(0.3)).setScale(2, BigDecimal.ROUND_HALF_DOWN).doubleValue();
        System.out.println(v);
    }

}
